﻿using System;
using System.Collections.Generic;
using Black.Surface2DEngine.Common.Args;

namespace Black.Surface2DEngine.Common
{
    /// <summary>
    /// Définie un tick pour le timer internte
    /// </summary>
    public class TimerItem: IDisposable, IComparable<TimerItem>
    {
        #region Variables d'instances

        private float m_fTick;
        private float m_fTickCount;
        private float? m_fLoop;
        private float m_fLoopMax;
        private Dictionary<string, Object> m_oParams;
        private EventHandler<TimerCallBackArgs> m_oDelegate;

        #endregion

        #region Constructeur

        /// <summary>
        /// Constructeur de la classe
        /// </summary>
        /// <param name="p_fTick">Indicateur de temps pour le raise du tick</param>
        /// <param name="p_oParams">Paramètres à l'event</param>
        /// <param name="p_oCallBack">Fonction de callback pour le tick</param>
        public TimerItem(float p_fTick, EventHandler<TimerCallBackArgs> p_oCallBack)
        {
            this.m_fLoop = null;
            this.m_fLoopMax = 0;
            this.m_fTick = p_fTick;
            this.m_fTickCount = 0.0f;
            this.m_oDelegate = p_oCallBack;
            this.m_oParams = new Dictionary<string, object>();
        }

        /// <summary>
        /// Libère les ressources
        /// </summary>
        public void Dispose()
        {
            this.m_oParams.Clear();
            this.m_oParams = null;
        }

        #endregion

        #region Fonctions publiques

        /// <summary>
        /// Ajoute un paramètre au tick
        /// </summary>
        /// <param name="p_sName">Nom du paramètre</param>
        /// <param name="p_oValue">Valeur du paramètre</param>
        public void AddParam(string p_sName, object p_oValue)
        {
            if ( this.m_oParams.ContainsKey(p_sName) )
                this.m_oParams[p_sName] = p_oValue;
            else
                this.m_oParams.Add(p_sName, p_oValue);
        }

        /// <summary>
        /// Lance le tick (pour le callback)
        /// </summary>
        /// <param name="p_fCurrentTick">Tick réel du raise</param>
        /// <param name="p_bIsAfter">TRUE est levé après l'update de l'écran, FALSE sinon</param>
        /// <returns>TRUE demande d'arrêt de la boucle, FALSE sinon</returns>
        public bool Raise(float p_fCurrentTick, bool p_bIsAfter)
        {
            bool bReturn = false;

            // Augmentation du compteur tick

            this.m_fTickCount++;

            // Envoi du délégué

            if ( this.m_oDelegate != null )
            {
                // Création du l'argument

                TimerCallBackArgs oArg = new TimerCallBackArgs(this, p_fCurrentTick, p_bIsAfter);

                // Gestion de l'initialisation du Cancel

                if ( this.m_fLoop != null && this.m_fLoopMax > 0.0f && this.m_fTickCount >= this.m_fLoopMax )
                    oArg.CancelLoop = true;

                // On raise le délégué

                this.m_oDelegate(this, oArg);

                // Gestion du retour cancel loop

                bReturn = oArg.CancelLoop;
            }

            return (bReturn);
        }

        /// <summary>
        /// Retire un paramètre du tick
        /// </summary>
        /// <param name="p_sName">Nom du paramètre</param>
        public void RemoveParam(string p_sName)
        {
            this.m_oParams.Remove(p_sName);
        }

        #endregion

        #region IComparable<TimerItem> Members

        /// <summary>
        /// Compare deux instances pour les trier
        /// </summary>
        /// <param name="other">Autre instance a tester</param>
        /// <returns>Indicateur de comparaison</returns>
        public int CompareTo(TimerItem other)
        {
            return (this.m_fTick.CompareTo(other.Tick));
        }

        #endregion

        #region Indexer

        /// <summary>
        /// Retourne si le timer est en mode boucle
        /// </summary>
        public bool IsLoop
        {
            get
            {
                return (this.m_fLoop != null);
            }
        }

        /// <summary>
        /// Affecte ou retourne l'interval de boucle
        /// </summary>
        public float? Loop
        {
            get
            {
                return (this.m_fLoop);
            }
            set
            {
                this.m_fLoop = value;
            }
        }

        /// <summary>
        /// Affecte ou retourne le nombre de boucle a faire (0 si infinie)
        /// </summary>
        public float LoopMax
        {
            get
            {
                return (this.m_fLoopMax);
            }
            set
            {
                this.m_fLoopMax = value;
            }
        }

        /// <summary>
        /// Retourne les paramètres du timer
        /// </summary>
        internal Dictionary<string, object> Params
        {
            get
            {
                return (this.m_oParams);
            }
        }

        /// <summary>
        /// Retourne le tick de raise
        /// </summary>
        public float Tick
        {
            get
            {
                return (this.m_fTick);
            }
            internal set
            {
                this.m_fTick = value;
            }
        }

        /// <summary>
        /// Retourne le nombre de tick déjà effectué
        /// </summary>
        public float TickCount
        {
            get
            {
                return (this.m_fTickCount);
            }
        }

        #endregion
    }
}
